<?php

namespace app\common\service;

use think\Exception;

class ElasticsearchService
{
    /**
     * Elasticsearch连接配置
     */
    protected $config = [
        'host'     => 'http://localhost:9200',
        'user'     => 'elastic',
        'password' => '123456',
//        'index'    => 'indexmain_v2',
        'index' => 'smhs_news'
    ];

    /**
     * cURL句柄
     */
    protected $ch;

    /**
     * 构造函数，初始化cURL
     */
    public function __construct()
    {
        // 测试主机是否可达
        $host = parse_url($this->config['host'], PHP_URL_HOST);
        $port = parse_url($this->config['host'], PHP_URL_PORT) ?: 9200;

        if (!@fsockopen($host, $port, $errno, $errstr, 5)) {
            throw new Exception("无法连接到 {$host}:{$port} - {$errstr} ({$errno})");
        }
        $this->ch = curl_init();
        // 设置通用的cURL选项
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($this->ch, CURLOPT_USERPWD, $this->config['user'] . ':' . $this->config['password']);
        curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($this->ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        // 测试连接
        $testUrl = $this->config['host'];
        curl_setopt($this->ch, CURLOPT_URL, $testUrl);
        // 在抛出异常前添加
        $info = curl_getinfo($this->ch);

        $response = curl_exec($this->ch);

        if (curl_errno($this->ch)) {
            throw new Exception("Elasticsearch连接失败: " . curl_error($this->ch));
        }

        $data = json_decode($response, true);
        if (!isset($data['version'])) {
            throw new Exception("Elasticsearch连接异常: " . $response);
        }
    }

    /**
     * 析构函数，关闭cURL连接
     */
    public function __destruct()
    {
        if ($this->ch) {
            curl_close($this->ch);
        }
    }

    /**
     * 执行Elasticsearch查询
     *
     * @param array $params 查询参数
     * @param string $method HTTP方法
     * @param string $endpoint 请求的端点
     * @return array 查询结果
     */
    protected function execute($params = [], $method = 'GET', $endpoint = '_search')
    {
        $url = $this->config['host'] . '/' . $this->config['index'] . '/' . $endpoint;

        curl_setopt($this->ch, CURLOPT_URL, $url);

        if ($method === 'POST') {
            curl_setopt($this->ch, CURLOPT_POST, true);
            curl_setopt($this->ch, CURLOPT_POSTFIELDS, json_encode($params));
        } else {
            curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $method);
            if (!empty($params)) {
                curl_setopt($this->ch, CURLOPT_POSTFIELDS, json_encode($params));
            }
        }

        $response = curl_exec($this->ch);


        if (curl_errno($this->ch)) {
            return ['error' => curl_error($this->ch)];
        }

        return json_decode($response, true);
    }

    /**
     * 构建通用查询条件
     *
     * @param array $conditions 查询条件
     * @return array 构建的查询参数
     */
    public function buildQuery($conditions = [], $page = 1, $size = 20)
    {
        $must     = [];
        $should   = [];
        $filter   = [];
        $must_not = [];

        // 添加基础过滤条件
        if (isset($conditions['delete_time'])) {
            $filter[] = ['term' => ['delete_time' => $conditions['delete_time']]];
        }

        if (isset($conditions['news_file_id'])) {
            $filter[] = ['term' => ['news_file_id' => $conditions['news_file_id']]];
        }

        // 处理地区过滤
        if (!empty($conditions['province'])) {
            $filter[] = ['term' => ['province.keyword' => $conditions['province']]];
        }

        if (!empty($conditions['city'])) {
            $filter[] = ['term' => ['city.keyword' => $conditions['city']]];
        }

        if (!empty($conditions['district'])) {
            $filter[] = ['term' => ['district.keyword' => $conditions['district']]];
        }

        // 处理分类过滤
        if (!empty($conditions['cate_one'])) {
            $filter[] = ['term' => ['cate_one' => $conditions['cate_one']]];
        }

        if (!empty($conditions['cate_two'])) {
            $filter[] = ['term' => ['cate_two' => $conditions['cate_two']]];
        }

        // 处理营业状态过滤
        if (!empty($conditions['status_in'])) {
            $filter[] = ['terms' => ['status.keyword' => $conditions['status_in']]];
        }

        // 处理联系方式过滤
        if (!empty($conditions['lianxi'])) {
            if ($conditions['lianxi'] == '有手机') {
                $filter[] = ['term' => ['has_mobile' => 1]];
            } elseif ($conditions['lianxi'] == '有固话') {
                $filter[] = [
                    'bool' => [
                        'must' => [
                            ['exists' => ['field' => 'mobile_more']],
                            ['range' => ['mobile_more' => ['gt' => '']]]
                        ]
                    ]
                ];
            } elseif ($conditions['lianxi'] == '有邮箱') {
                $filter[] = [
                    'bool' => [
                        'must' => [
                            ['exists' => ['field' => 'emails']],
                            ['range' => ['emails' => ['gt' => '']]]
                        ]
                    ]
                ];
            } elseif ($conditions['lianxi'] == '有QQ') {
                $filter[] = [
                    'bool' => [
                        'must' => [
                            ['exists' => ['field' => 'qq']],
                            ['range' => ['qq' => ['gt' => '']]]
                        ]
                    ]
                ];
            } elseif ($conditions['lianxi'] == '无联系方式') {
                // 修改无联系方式的查询逻辑
                $must_not[] = [
                    'bool' => [
                        'should'               => [
                            ['range' => ['mobile' => ['gt' => '']]],
                            ['range' => ['mobile_more' => ['gt' => '']]]
                        ],
                        'minimum_should_match' => 1
                    ]
                ];
            }
        }

        // 处理日期年限过滤
        if (!empty($conditions['riqi_year'])) {
            if ($conditions['riqi_year'] == '1年以内') {
                $filter[] = ['range' => ['riqi_year' => ['lte' => 1]]];
            } elseif ($conditions['riqi_year'] == '15年以上') {
                $filter[] = ['range' => ['riqi_year' => ['gte' => 15]]];
            } else {
                $years = explode('-', $conditions['riqi_year']);
                if (count($years) == 2) {
                    $filter[] = ['range' => ['riqi_year' => ['gte' => (int)$years[0], 'lte' => (int)$years[1]]]];
                }
            }
        }

        // 处理注册资金过滤
        if (!empty($conditions['zhuce'])) {
            if ($conditions['zhuce'] == '20万以下') {
                $filter[] = ['range' => ['zhuce_amount' => ['lt' => 200000]]];
            } elseif ($conditions['zhuce'] == '500万以上') {
                $filter[] = ['range' => ['zhuce_amount' => ['gte' => 5000000]]];
            } else {
                $zhuce = explode('~', $conditions['zhuce']);
                if (count($zhuce) == 2) {
                    $filter[] = ['range' => ['zhuce_amount' => ['gte' => (int)$zhuce[0] * 10000, 'lte' => (int)$zhuce[1] * 10000]]];
                }
            }
        }

        // 处理企业类型过滤
        if (!empty($conditions['leixing'])) {
            $filter[] = ['match_phrase' => ['leixing' => $conditions['leixing']]];
        }

        // 处理参保人数过滤
        if (!empty($conditions['canbao'])) {
            if ($conditions['canbao'] == '小于20人') {
                $filter[] = ['range' => ['canbao' => ['lt' => 20]]];
            } else {
                $canbao = explode('-', $conditions['canbao']);
                if (count($canbao) == 2) {
                    $filter[] = ['range' => ['canbao' => ['gte' => (int)$canbao[0], 'lte' => (int)$canbao[1]]]];
                }
            }
        }

        // 处理其他布尔条件
        foreach (['zhaopin', 'wangluo', 'yuming', 'shangbiao', 'zhuanli', 'zhaobiao', 'gongzhong'] as $field) {
            if (!empty($conditions[$field])) {
                $filter[] = ['term' => [$field . '.keyword' => $conditions[$field]]];
            }
        }

        // 处理关键词搜索
        if (!empty($conditions['keys'])) {
            $should[] = [
                'multi_match' => [
                    'query'  => $conditions['keys'],
                    'fields' => ['name^5', 'daima', 'faren', 'province', 'city', 'district', 'leixing'], //, 'province', 'city', 'district', 'address'
                    'type'   => 'phrase_prefix'
                ]
            ];
        }

        // 构建查询
        $query = [
            'query' => [
                'bool' => []
            ],

            "_source" => ["id", "name", "mobile", "daima", "faren", "province", "city", "address", "create_time", "district", "zhuce", "status", "riqi"],
            // 'sort' => [
            //     ['id' => ['order' => 'desc']]
            // ],
            "sort"    => [

                [
                    "has_mobile" => [
                        "order" => "desc"
                    ]
                ]
                ,

                [
                    "is_status_active" => [
                        "order" => "desc"
                    ]
                ],
                [
                    "riqi" => [
                        "order" => "desc"
                    ]
                ]

            ],


            'from'             => ($page - 1) * $size,
            'size'             => $size,
            'track_total_hits' => true
            // 'from' => 0,
            // 'size' => 20000,
            // 'track_total_hits' => true
        ];

        if (!empty($must)) {
            $query['query']['bool']['must'] = $must;
        }

        if (!empty($should)) {
            $query['query']['bool']['should']               = $should;
            $query['query']['bool']['minimum_should_match'] = 1;
        }

        if (!empty($filter)) {
            $query['query']['bool']['filter'] = $filter;
        }

        if (!empty($must_not)) {
            $query['query']['bool']['must_not'] = $must_not;
        }

        return $query;
    }

    /**
     * 查询企业信息
     *
     * @param array $conditions 查询条件
     * @param int $page 页码
     * @param int $pageSize 每页数量
     * @return array 查询结果
     */
    public function searchNews($conditions, $page = 1, $pageSize = 20)
    {
        $query = $this->buildQuery($conditions, $page, $pageSize);
        $result = $this->execute($query, 'POST');

        $list  = [];
        $total = 0;

        if (!isset($result['error']) && isset($result['hits'])) {
            $total    = $result['hits']['total']['value'];
            $relation = $result['hits']['total']['relation'] ?? 'eq';

            // 记录查询结果的总数信息
            $logInfo = date('Y-m-d H:i:s') . " - 查询条件: " . json_encode($conditions, JSON_UNESCAPED_UNICODE) .
                       ", 总匹配数: {$total}, 关系: {$relation}, 返回数: " . count($result['hits']['hits']);
            error_log($logInfo, 3, runtime_path() . 'elasticsearch_query.log');

            foreach ($result['hits']['hits'] as $hit) {
                $item = $hit['_source'];
                // 确保title字段映射到name字段
                if (isset($item['name'])) {
                    $item['name'] = $item['name'];
                }
                if (isset($item['riqi'])) {
                    $item['riqi'] = $item['riqi'];
                }
                // 确保所有必要的字段存在
                if (empty($item['mobile_more'])) {
                    $item['mobile_more'] = '';
                }
                if (empty($item['mobile'])) {
                    $item['mobile'] = '';
                }
                $list[] = $item;
            }
        }

        return [
            'list'  => $list,
            'total' => $total
        ];
    }

    /**
     * 获取所有匹配的ID
     *
     * @param array $conditions 查询条件
     * @param int $limit 限制数量
     * @return array ID列表和总记录数
     */
    public function getAllIds($conditions, $page = 1, $limit = 1000000)
    {
        $query                     = $this->buildQuery($conditions, $page, $limit);
        $query['_source']          = ['id'];
        $query['track_total_hits'] = false;
        $result                    = $this->execute($query, 'POST');
        $ids                       = [];
        $total                     = 0;

        if (!isset($result['error']) && isset($result['hits'])) {
            //     $total = $result['hits']['total']['value'];
            $total    = 0;
            $relation = $result['hits']['total']['relation'] ?? 'eq';

            // 记录查询结果的总数信息
            $logInfo = date('Y-m-d H:i:s') . " - 获取ID - 查询条件: " . json_encode($conditions, JSON_UNESCAPED_UNICODE) .
                       ", 总匹配数: {$total}, 关系: {$relation}, 实际获取ID数: " . count($result['hits']['hits']) .
                       ", 限制数: {$limit}";
            error_log($logInfo, 3, runtime_path() . 'elasticsearch_ids.log');

            foreach ($result['hits']['hits'] as $hit) {
                if (isset($hit['_source']['id'])) {
                    $ids[] = $hit['_source']['id'];
                }
            }
        }

        return [
            'ids'   => $ids,
            'total' => $total
        ];
    }

    /**
     * 批量写入 news 到 ES
     * @param array $newsList
     * @param string $indexName
     * @return array
     * @throws Exception
     */
    public function bulkInsertNews(array $newsList, $indexName = 'smhs_news')
    {
        if (empty($newsList)) {
            return ['success' => true, 'msg' => 'empty'];
        }
        $body = '';
        foreach ($newsList as $row) {
            // 推荐加主键做_id，方便去重/覆盖
            $meta = ['index' => ['_index' => $indexName, '_id' => $row['id']]];
            $body .= json_encode($meta, JSON_UNESCAPED_UNICODE) . "\n";
            $body .= json_encode($row, JSON_UNESCAPED_UNICODE) . "\n";
        }
        $url = rtrim($this->config['host'], '/') . '/_bulk';
        curl_setopt($this->ch, CURLOPT_URL, $url);
        curl_setopt($this->ch, CURLOPT_POST, true);
        curl_setopt($this->ch, CURLOPT_POSTFIELDS, $body);
        $response = curl_exec($this->ch);

        if (curl_errno($this->ch)) {
            throw new Exception("ES写入失败: " . curl_error($this->ch));
        }
        $result = json_decode($response, true);
        if (isset($result['errors']) && $result['errors']) {
            // 写入有失败
            return ['success' => false, 'response' => $result];
        }
        return ['success' => true, 'count' => count($newsList)];
    }

    /**
     * 查询ES内数据
     * @param array $conditions 支持 id, name, status 等字段
     * @param int $page
     * @param int $size
     * @param string|null $indexName
     * @return array
     */
    public function getEsData($conditions = [], $page = 1, $size = 20, $indexName = null)
    {
        $index = $indexName ?: $this->config['index'];

        $query = [
            'query' => [
                'bool' => [
                    'must' => []
                ]
            ],
            'from' => ($page - 1) * $size,
            'size' => $size,
            'sort' => [['id' => ['order' => 'asc']]]
        ];

        // 简单条件支持
        foreach (['id', 'name', 'status'] as $field) {
            if (!empty($conditions[$field])) {
                $query['query']['bool']['must'][] = [
                    'term' => [$field => $conditions[$field]]
                ];
            }
        }

        // 支持 fuzzy name 查询
        if (!empty($conditions['name_fuzzy'])) {
            $query['query']['bool']['must'][] = [
                'match' => ['name' => $conditions['name_fuzzy']]
            ];
        }

        $result = $this->executeEsQuery($query, $index);

        $data  = [];
        $total = 0;
        if (!isset($result['error']) && isset($result['hits'])) {
            $total = $result['hits']['total']['value'] ?? 0;
            foreach ($result['hits']['hits'] as $hit) {
                $data[] = $hit['_source'];
            }
        }
        return ['total' => $total, 'list' => $data];
    }

    /**
     * 执行ES原生查询
     * @param array $query
     * @param string $indexName
     * @return array
     */
    protected function executeEsQuery($query, $indexName)
    {
        $url = $this->config['host'] . '/' . $indexName . '/_search';
        curl_setopt($this->ch, CURLOPT_URL, $url);
        curl_setopt($this->ch, CURLOPT_POST, true);
        curl_setopt($this->ch, CURLOPT_POSTFIELDS, json_encode($query, JSON_UNESCAPED_UNICODE));
        $response = curl_exec($this->ch);
        if (curl_errno($this->ch)) {
            return ['error' => curl_error($this->ch)];
        }
        return json_decode($response, true);
    }
} 